//
//  ACNetWorkTool.m
//  ACLiteAVUISDK
//
//  Created by 冯琰琰 on 2021/4/12.
//

#import "ACNetWorkTool.h"
#import "MobileCoreServices/MobileCoreServices.h"

@interface ACNetWorkTool ()

@property(nonatomic, strong)NSSet *closeErrorSet;//封禁错误集合

@end

@implementation ACNetWorkTool

+ (instancetype)shareRequestManager
{
    static ACNetWorkTool *_shareInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _shareInstance = [[super alloc] init];
        _shareInstance.status = AFNetworkReachabilityStatusUnknown;
        // 开启监听网络变化
        [ACNetWorkTool getNetworkStates];
        AFJSONResponseSerializer * _Nonnull jsonSerial = [AFJSONResponseSerializer serializer];
        [jsonSerial setRemovesKeysWithNullValues:YES];
        _shareInstance.responseSerializer = jsonSerial;
        _shareInstance.requestSerializer = [AFJSONRequestSerializer serializer];
        // 设置请求超时
        [_shareInstance.requestSerializer willChangeValueForKey:@"timeoutInterval"];
        _shareInstance.requestSerializer.timeoutInterval = TIMEOUT_INTERVAL;
        [_shareInstance.requestSerializer didChangeValueForKey:@"timeoutInterval"];
        // 是否校验无效证书 默认为NO
        _shareInstance.securityPolicy.allowInvalidCertificates = YES;
        // 是否校验无效域名 默认为YES
        _shareInstance.securityPolicy.validatesDomainName = NO;
        [_shareInstance.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
        [_shareInstance.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
        _shareInstance.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/plain", nil];
        _shareInstance.sem = dispatch_semaphore_create(1);
        _shareInstance.queue = dispatch_queue_create(0, DISPATCH_QUEUE_CONCURRENT);
    });
    return _shareInstance;
}

-(NSMutableDictionary *)retryCountDic {
    if (!_retryCountDic) {
        _retryCountDic = [NSMutableDictionary dictionary];
    }
    return _retryCountDic;
}

- (NSMutableDictionary *)addDefaultHeader{
    NSMutableDictionary * dic = [NSMutableDictionary dictionary];
//    NSString *network = @"Unknown";
//    switch ([ACNetWorkTool shareRequestManager].status) {
//        case AFNetworkReachabilityStatusUnknown:
//            network = @"Unknown";
//            break;
//        case AFNetworkReachabilityStatusNotReachable:
//            network = @"NotReachable";
//            break;
//        case AFNetworkReachabilityStatusReachableViaWiFi:
//            network = @"WiFi";
//            break;
//        case AFNetworkReachabilityStatusReachableViaWWAN:
//            network = @"WWAN";
//            break;
//        default:
//            break;
//    }
    NSString *token_user = [[ACUserProfileManager shareInstance] getToken];
    if (![token_user isEqualToString:@""]) {
        NSString *token = [NSString stringWithFormat:@"Bearer %@",token_user];
        [dic setValue:token forKey:@"Authorization"];
        [dic enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) {
            [self.requestSerializer setValue:value forHTTPHeaderField:key];
        }];
    }
    return dic;
}
/// 设置默认参数
/// @param params 提交参数
/// @param method 请求类型
/// @param path 接口地址
- (NSMutableDictionary *)addDefaultPar:(id)params method:(NSString *)method path:(NSString *)path{
    //    添加默认请求头参数
    [[ACNetWorkTool shareRequestManager] addDefaultHeader];
    NSURL * url = [NSURL URLWithString:path];
    [[ACNetWorkTool shareRequestManager].requestSerializer setValue:url.host forHTTPHeaderField:@"host"];
//    //    如果是统一用户中心的话，因为它只有两个环境，所以需要区分
//    if ([url.host isEqualToString:@"user.api.fltrp.com"]) {
//        if ([FLDataCacheModule getAppSeverEvirn] == FLAppSeverEvirnRelease) {
//            [[ACNetWorkTool shareRequestManager].requestSerializer setValue:@"RELEASE" forHTTPHeaderField:@"X-Ca-Stage"];
//        }else{
//            [[ACNetWorkTool shareRequestManager].requestSerializer setValue:@"TEST" forHTTPHeaderField:@"X-Ca-Stage"];
//        }
//    }
    //    除了检测更新token的接口，每次调用的时候都要检测刷新token

//    if (![path containsString:@"/sso/wys/online/refreshToken"]) {
//        [FLConfigManager updateTokenForce:NO Success:nil Failed:nil];
//    }
//    path = url.path;
    //    如果是字典，添加默认提交参数
    NSMutableDictionary * dic = [NSMutableDictionary dictionary];
//    if ([params isDictionary]) {
//        [dic setDictionary:params];
//        if ([FLDeviceInfoModule getAPPEnvir] == FLAPPEnvirTypeStudent){
//            [dic setValue:[FLStuInfoManager getUserModel].stuId forKey:@"stuId"];
//        }else if ([FLDeviceInfoModule getAPPEnvir] == FLAPPEnvirTypeTeacher){
//            [dic setValue:[FLTeacherInfoManager getUserModel].orgId forKey:@"orgId"];
//            [dic setValue:[FLTeacherInfoManager getUserModel].ID forKey:@"tchId"];
//        }
//        //添加 APIGatewayHeader
//        [FLAPIGatewayManager addAPIGatewayHeaderWithParam:dic method:method netWorkModule:[ACNetWorkTool shareRequestManager] path:path];
//        return dic;
//    }else{
//        //添加 APIGatewayHeader
//        [FLAPIGatewayManager addAPIGatewayHeaderWithParam:params method:method netWorkModule:[ACNetWorkTool shareRequestManager] path:path];
//        return params;
//    }
    [dic setDictionary:params];
    return dic;
}

- (NSURLSessionDataTask *)get:(NSString *)url params:(id)params success:(void (^)(id responseObject))success failure:(void (^)(NSError *error))failure
{
    [self checkNetwork];
    NSMutableDictionary *paramsM = [self addDefaultPar:params method:@"GET" path:url];
    NSURLSessionDataTask * dataTask = [[ACNetWorkTool shareRequestManager] GET:url parameters:paramsM headers:nil progress:^(NSProgress * _Nonnull downloadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [self checkResponseObjectWithTask:task responseObject:responseObject paramsM:paramsM url:url fileName:@"" success:success failure:failure];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [self invalidTokenRetryWithTask:task needRetry:^{
            [self get:url params:params success:success failure:failure];
        } forbidRetry:^{
            [self responseWithTask:task error:error withUrl:url withParams:params failure:failure];
        }];
    }];
    if (self.requestDelegate && [self.requestDelegate respondsToSelector:@selector(startRequestWithTask:paramsM:url:fileName:)]) {
        [self.requestDelegate startRequestWithTask:dataTask paramsM:paramsM url:url fileName:@""];
    }
    return dataTask;
    
}

- (NSURLSessionDataTask *)post:(NSString *)url contentType:( NSString * _Nullable)contentType params:(id _Nullable)params success:(void (^)(id responseObject))success failure:(void (^)(NSError *error))failure{
    [self checkNetwork];
    NSURLSessionDataTask * dataTask = nil;
    NSString *dns = url;
    NSMutableDictionary *paramsM = [self addDefaultPar:params method:@"POST" path:url];
    if ([contentType isEqualToString:@"form"]) {
        [self.requestSerializer setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
        dataTask = [self POST:dns parameters:paramsM headers:nil constructingBodyWithBlock:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            [self checkResponseObjectWithTask:task responseObject:responseObject paramsM:paramsM url:url fileName:@"" success:success failure:failure];
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            [self invalidTokenRetryWithTask:task needRetry:^{
                [self post:url contentType:contentType params:params success:success failure:failure];
            } forbidRetry:^{
                [self responseWithTask:task error:error withUrl:url withParams:params failure:failure];
            }];
        }];
    }else if([contentType isEqualToString:@"form-data"]){
        [self.requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"];
        dataTask = [self POST:dns parameters:paramsM headers:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
            for (NSString *key in [paramsM allKeys]) {
                    [formData appendPartWithFileData:[paramsM objectForKey:key] name:@"file" fileName:@"cover.png" mimeType:@"image/png"];
                }
        } progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            [self checkResponseObjectWithTask:task responseObject:responseObject paramsM:paramsM url:url fileName:@"" success:success failure:failure];
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            [self invalidTokenRetryWithTask:task needRetry:^{
                [self post:url contentType:contentType params:params success:success failure:failure];
            } forbidRetry:^{
                [self responseWithTask:task error:error withUrl:url withParams:params failure:failure];
            }];
        }];

    } else {
        [self.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
        dataTask = [[ACNetWorkTool shareRequestManager] POST:url parameters:paramsM headers:nil progress:^(NSProgress * _Nonnull uploadProgress) {
            
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            [self checkResponseObjectWithTask:task responseObject:responseObject paramsM:paramsM url:url fileName:@"" success:success failure:failure];
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            [self invalidTokenRetryWithTask:task needRetry:^{
                [self post:url contentType:contentType params:params success:success failure:failure];
            } forbidRetry:^{
                [self responseWithTask:task error:error withUrl:url withParams:params failure:failure];
            }];
        }];
    }
    if (self.requestDelegate && [self.requestDelegate respondsToSelector:@selector(startRequestWithTask:paramsM:url:fileName:)]) {
        [self.requestDelegate startRequestWithTask:dataTask paramsM:paramsM url:url fileName:@""];
    }
    return dataTask;
}
- (NSURLSessionDataTask *)post:(NSString *)url params:(id)params success:(void (^)(id responseObject))success failure:(void (^)(NSError *error))failure
{
    return [self post:url contentType:nil params:params success:success failure:failure];
}
- (NSURLSessionDataTask *)del:(NSString *)url params:(id)params success:(void (^)(id _Nonnull))success failure:(void (^)(NSError * _Nonnull))failure
{
    [self checkNetwork];
//    NSDictionary *defaultHeader = [self addDefaultHeader];
    NSMutableDictionary *paramsM = [self addDefaultPar:params method:@"DEL" path:url];
    NSURLSessionDataTask *dataTask = [[ACNetWorkTool shareRequestManager] DELETE:url parameters:paramsM headers:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [self checkResponseObjectWithTask:task responseObject:responseObject paramsM:paramsM url:url fileName:@"" success:success failure:failure];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [self responseWithTask:task error:error withUrl:url withParams:params failure:failure];
    }];
    if (self.requestDelegate && [self.requestDelegate respondsToSelector:@selector(startRequestWithTask:paramsM:url:fileName:)]) {
        [self.requestDelegate startRequestWithTask:dataTask paramsM:paramsM url:url fileName:@""];
    }
    return dataTask;
}
- (NSURLSessionDataTask *)put:(NSString *)url params:(id)params success:(void (^)(id responseObject))success failure:(void (^)(NSError *error))failure{
    [self checkNetwork];
    NSMutableDictionary *paramsM = [self addDefaultPar:params method:@"PUT" path:url];
    NSURLSessionDataTask * dataTask = [[ACNetWorkTool shareRequestManager] PUT:url parameters:paramsM headers:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [self checkResponseObjectWithTask:task responseObject:responseObject paramsM:paramsM url:url fileName:@"" success:success failure:failure];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        //        failure(error);
        [self responseWithTask:task error:error withUrl:url withParams:params failure:failure];
    }];
    if (self.requestDelegate && [self.requestDelegate respondsToSelector:@selector(startRequestWithTask:paramsM:url:fileName:)]) {
        [self.requestDelegate startRequestWithTask:dataTask paramsM:paramsM url:url fileName:@""];
    }
    return dataTask;
}
#pragma mark 成功检测
- (void)checkResponseObjectWithTask:(NSURLSessionDataTask* __unused)task
                     responseObject:(id)responseObject
                            paramsM:(NSMutableDictionary *)paramsM
                                url:(NSString *)url
                           fileName:(NSString *)fileName
                            success:(void (^)(id responseObject))success
                            failure:(void (^)( NSError* error))failure{
    if (self.requestDelegate && [self.requestDelegate respondsToSelector:@selector(requestSuccessWithTask:responseObject:paramsM:url:fileName:)]) {
        [self.requestDelegate requestSuccessWithTask:task responseObject:responseObject paramsM:paramsM url:url fileName:fileName];
    }
//    if (!([responseObject isKindOfClass:[NSDictionary class]])) {
//        DDLogInfo(@"返回信息有误，不是JSON");
//        if (failure) {
//            NSDictionary* userInfo = [NSDictionary dictionaryWithObject:NetErrorWithIncorrectformatInfo forKey:NSLocalizedDescriptionKey];
//            NSError* aError = [NSError errorWithDomain:NetErrorWithIncorrectformatDomain code:40000 userInfo:userInfo];
//            failure(aError);
//            [self requestDelegateRequestFailedWithTask:task responseObject:responseObject error:aError params:paramsM url:url fileName:fileName];
//        }
//        return;
//    }
    NSHTTPURLResponse * respone = (NSHTTPURLResponse *)task.response;
    if (respone.statusCode == 200 || respone.statusCode == 204) { // 成功
        if (respone.statusCode == 200) {
            success([responseObject valueForKeyPath:@"data"]);
        }else{
            success(@{@"code":@"111"});
        }
    }else{
        NSDictionary * dictData = (NSDictionary *)responseObject;
        NSString * msg = [dictData valueForKey:@"errors"];
        NSString * code = [dictData valueForKey:@"code"];
//        if ([self changeNetErrorCode:code andMsg:msg]) { // 需要处理的账号异常情况 暂时不考虑
//
//        }else{
        NSMutableDictionary * userInfo = [NSMutableDictionary dictionaryWithDictionary:[NSDictionary dictionaryWithObject:msg forKey:NSLocalizedDescriptionKey]];
        [userInfo setValue:code forKey:NSLocalizedFailureReasonErrorKey];
        NSError* aError = [NSError errorWithDomain:code code:NETReturnErrorCode userInfo:userInfo];
        failure(aError);
//        }
    }
}
- (BOOL)changeNetErrorCode:(NSString *)code andMsg:(NSString *)msg{
    BOOL exitCodeBool = NO;
    if ([code isEqualToString:@"update"]) {
        exitCodeBool = YES;
    }else if ([code isEqualToString:@"stuCancelError"]) {
        [SVProgressHUD showInfoWithStatus:msg];
        exitCodeBool = YES;
    }else if ([self.closeErrorSet containsObject:code]) {
        if ([msg isEqualToString:@""]) {
            [SVProgressHUD showInfoWithStatus:@"您的账号已被封禁或关闭，不能登录"];
        }else{
            [SVProgressHUD showInfoWithStatus:msg];
        }
        exitCodeBool = YES;
    }else if ([code isEqualToString:@"accountExpireError"]) {
        [SVProgressHUD showInfoWithStatus:@"您的体验账号已到期，暂无法登录"];
        exitCodeBool = YES;
    }
    return exitCodeBool;
}

- (NSSet *)closeErrorSet{
    if (!_closeErrorSet) {
        _closeErrorSet = [NSSet setWithObjects:@"stuCloseError",@"tchCloseError",@"orgCloseError",@"orgInvalidError",@"userCloseError",@"accountError",@"SsoCheckError",@"SsoOutTimeError", @"SsoNotExistUserError", @"UserIdNotBlank", nil];
    }
    return _closeErrorSet;
}

#pragma mark 请求失败
-(void)invalidTokenRetryWithTask:(NSURLSessionDataTask* __unused)task needRetry:(void (^)(void))needRetry forbidRetry:(void (^)(void))forbidRetry {
    NSHTTPURLResponse * respone = (NSHTTPURLResponse *)task.response;
    NSDictionary * headerFields = respone.allHeaderFields;
    NSString * msg = [headerFields valueForKey:@"X-Ca-Error-Message"];
    BOOL invalid = NO;
    if (![msg isEqualToString:@""]) {
        if ([[msg lowercaseString] containsString:@"jwt"]) {
            invalid = YES;
        }
    }
    if (invalid) {
        // token 失效
        NSString *key = task.currentRequest.URL.absoluteString;
        NSNumber *count = [self.retryCountDic valueForKey:key];
        int countValue = [count intValue];
        if (countValue > 2) {
            // 次数限制
            if (forbidRetry) {
                forbidRetry();
            }
            countValue = 0;
            [self.retryCountDic setValue:[NSNumber numberWithInt:countValue] forKey:key];
        } else {
            countValue += 1;
            [self.retryCountDic setValue:[NSNumber numberWithInt:countValue] forKey:key];
//            [FLConfigManager updateTokenForce:YES Success:^{
//                if (needRetry) {
//                    needRetry();
//                }
//            } Failed:^{
//                if (forbidRetry) {
//                    forbidRetry();
//                }
//            }];
        }
    } else {
        if (forbidRetry) {
            forbidRetry();
        }
    }
    
}
-(void)responseWithTask:(NSURLSessionDataTask* __unused)task error:(NSError *)error withUrl:(NSString *)url withParams :(NSDictionary *)parmas failure:(void (^)( NSError* error))failure{
    
    NSMutableDictionary * userInfo = [NSMutableDictionary dictionary];
    NSError *e;
    NSDictionary *errorInfoDic = [NSJSONSerialization JSONObjectWithData:error.userInfo[@"com.alamofire.serialization.response.error.data"] options:NSJSONReadingMutableLeaves error:&e];
    NSString *msg = [errorInfoDic objectForKey:@"errors"];
    NSInteger code = [[errorInfoDic objectForKey:@"code"] integerValue];
    error = [NSError errorWithDomain:msg code:code userInfo:userInfo];
    
    failure(error);
    
    [self requestDelegateRequestFailedWithTask:task responseObject:@{} error:error params:parmas url:url fileName:@""];
    
}
- (void)requestDelegateRequestFailedWithTask:(NSURLSessionDataTask* __unused)task responseObject:(id)responseObject error:(NSError *)error params:(NSDictionary *)parmas url:(NSString *)url fileName:(NSString *)fileName{
    if (self.requestDelegate && [self.requestDelegate respondsToSelector:@selector(requestFailedWithTask:responseObject:error:params:url:fileName:)]) {
        [self.requestDelegate requestFailedWithTask:task responseObject:responseObject error:error params:parmas url:url fileName:fileName];
    }
}
+ (void)getNetworkStates {
    // 监控网络状态
    AFNetworkReachabilityManager *reachability = [AFNetworkReachabilityManager sharedManager];
    [reachability setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        [ACNetWorkTool shareRequestManager].status = status;
        switch (status) {
            case AFNetworkReachabilityStatusUnknown:
               
                DDLogInfo(@"AFNetworkReachabilityStatus 状态不知道");
                break;
            case AFNetworkReachabilityStatusNotReachable:
               
                DDLogInfo(@"AFNetworkReachabilityStatus 没网络");
                break;
            case AFNetworkReachabilityStatusReachableViaWiFi:
               
                DDLogInfo(@"AFNetworkReachabilityStatus WIFI");
                break;
            case AFNetworkReachabilityStatusReachableViaWWAN:
               
                DDLogInfo(@"AFNetworkReachabilityStatus 流量");
                break;
            default:
                break;
        }
    }];
    //开始监控
    [reachability startMonitoring];
}
- (void)checkNetwork {
    
}

-(void)uploadFile:(NSString *)url filePath:(NSString *)filePath progress:(void (^)(NSProgress * _Nonnull uploadProgress))progress success:(void (^)(id responseObject))success failure:(void (^)(NSError *error))failure{
    NSData *fileData = [NSData dataWithContentsOfFile:filePath];
    NSString *fileName =[[filePath lastPathComponent] lowercaseString];
    NSString *MimeType = [self mimeTypeForFileAtPath:filePath];
//    NSString *MimeType = @"multipart/form-data";
    //policy 0不公开\1公开
    NSDictionary *params = @{@"title":fileName,@"policy":@"1"};
    NSMutableDictionary *paramsM = [self addDefaultPar:params method:@"POST" path:url];
    [[ACNetWorkTool shareRequestManager] POST:url parameters:paramsM headers:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        [formData appendPartWithFileData:fileData name:@"file" fileName:fileName mimeType:MimeType];
        } progress:^(NSProgress * _Nonnull uploadProgress) {
            DDLogInfo(@"上传进度---%f",uploadProgress.fractionCompleted);
            progress(uploadProgress);
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            DDLogInfo(@"上传成功");
            success(responseObject);
            NSDictionary *dic = [responseObject valueForKey:@"data"];
            
            NSString *fileId = [[dic objectForKey:@"id"] stringValue];
            [self transcodingFile:fileId];
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            DDLogInfo(@"上传失败");
            failure(error);
        }];
}

// 获取文件的MIMEType
//导入 #import "MobileCoreServices/MobileCoreServices.h"
- (NSString *)mimeTypeForFileAtPath:(NSString *)path
{
    // 这里使用文件管理者的相关方法判断文件路径是否有后缀名
    if (![[[NSFileManager alloc] init] fileExistsAtPath:path]) {
        return nil;
    }
    // [path pathExtension] 获得文件的后缀名 MIME类型字符串转化为UTI字符串
    CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[path pathExtension], NULL);
    // UTI字符串转化为后缀扩展名
    CFStringRef MIMEType = UTTypeCopyPreferredTagWithClass (UTI, kUTTagClassMIMEType);
    CFRelease(UTI);
    // application/octet-stream，此参数表示通用的二进制类型。
    if (!MIMEType) {
        return @"application/octet-stream";
    }
    NSString *resultStr = (__bridge NSString *)(MIMEType);
    CFRelease(MIMEType);
    return resultStr;
}

-(void)transcodingFile:(NSString *)fileId{
    NSString *url = [HOSTURL stringByAppendingString:@"/api/v1/material/transcode/"];
    url = [url stringByAppendingString:fileId];
    [self post:url params:[NSDictionary dictionary] success:^(id  _Nonnull responseObject) {
            DDLogInfo(@"转码成功");
        } failure:^(NSError * _Nonnull error) {
            DDLogInfo(@"转码失败");
        }];
}

@end
